#include "GUILane.h"
#include "GUINest.h"
#include "Part.h"
//adding multiple parts at the same time
//setting the done variable at end of lane
// 
/**
 * @fn	GUILane::GUILane(int X, int Y,int capacity,GUINest* nest,const QList<QPixmap> &animation,
 * 		QGraphicsScene *scene)
 *
 * @brief	Constructor.
 *
 * @author	Ben White
 *
 * @param	X			 	The X coordinate.
 * @param	Y			 	The Y coordinate.
 * @param	capacity		 	The capacity.
 * @param [in,out]	nest 	If non-null, the nest.
 * @param	animation	 	The animation.
 * @param [in,out]	scene	If non-null, the scene.
 */

GUILane::GUILane(int startX, int startY,int capacity,GUINest* nest, LaneColor laneColor)
	: GUIBase()
{
	switch (laneColor)
	{
	case LaneColor_Yellow: loadImage("Resources/Sprites/Lane/Lane1.png"); break;
	case LaneColor_Purple: loadImage("Resources/Sprites/Lane/Lane2.png"); break;
	case LaneColor_Green: loadImage("Resources/Sprites/Lane/Lane3.png"); break;
	case LaneColor_Red: loadImage("Resources/Sprites/Lane/Lane4.png"); break;
	}

	this->setX(startX);//moves the lane to the given coordinates
	this->setY(startY);
	this->setZValue(ZVALUE_LANE);
	Width=30;//sets width of lane
	PartSize=12;//size of parts(to prevent overlapping when parts back up
	EndX=this->boundingRect().width()+this->x();//sets the location of the end of the list
	Length=this->boundingRect().width();
	//qDebug()<<EndX;
	MidY=startY+(Width/2)+PartSize/2;//represnts starting Y coordinate of Parts for this lane
	Next=NULL; 
	Neighbor=NULL;
	//moveTo(x(),y());
	
	Running=false;//lane starts in the off state
	Broken=false;
	NumberOfParts=0;//counter for number of parts
	Capacity=capacity;//Number of parts the lane can carry
	Speed=0;//initializes speed
	LastSpeed=Speed;
	Nest=nest;//nest this lane feeds in to
}

/**
 * @fn	GUILane::GUILane(int startX, int startY,GUINest* nest, LaneColor laneColor)
 *
 * @brief	Constructor.
 *
 * @author	Ben White
 *
 * @param	startX			The start x coordinate.
 * @param	startY			The start y coordinate.
 * @param [in,out]	nest	If non-null, the nest.
 * @param	laneColor   	The lane color.
 */

GUILane::GUILane(int startX, int startY,GUINest* nest, LaneColor laneColor)
	: GUIBase()
{
	switch (laneColor)
	{
	case LaneColor_Yellow: loadImage("Resources/Sprites/Lane1.png"); break;
	case LaneColor_Purple: loadImage("Resources/Sprites/Lane2.png"); break;
	case LaneColor_Green: loadImage("Resources/Sprites/Lane3.png"); break;
	case LaneColor_Red: loadImage("Resources/Sprites/Lane4.png"); break;
	}

	this->setX(startX);//moves the lane to the given coordinates
	this->setY(startY);
	this->setZValue(ZVALUE_LANE);
	Width=30;//sets width of lane
	PartSize=12;//size of parts(to prevent overlapping when parts back up
	EndX=this->boundingRect().width()+this->x();//sets the location of the end of the list
	Length=this->boundingRect().width();
	//qDebug()<<EndX;
	MidY=startY+(Width/2)+PartSize/2;//represnts starting Y coordinate of Parts for this lane
	Next=NULL; 
	Neighbor=NULL;
	Jam = NULL;
	//moveTo(x(),y());
	
	Running=false;//lane starts in the off state
	Broken=false;
	NumberOfParts=0;//counter for number of parts
	Capacity=Length/PartSize;//Number of parts the lane can carry
	Speed=0;//initializes speed
	LastSpeed=Speed;
	Nest=nest;//nest this lane feeds in to
}

/**
 * @fn	void GUILane::setRunSpeed(float speed)
 *
 * @brief	Sets a run speed.
 *
 * @author	Ben White
 *
 * @param	speed	The speed.
 */

void GUILane::setRunSpeed(float speed)
{
	if(!Broken)
	{
		if(speed>Speed)
			Jam=NULL;
		Speed=speed;//
		for(int ii=0 ; ii<NumberOfParts ; ii++)//loop through all parts in lane and set speed=Speed
		{
			PartsInLane[ii]->setMovementSpeed(Speed);
		}
		LastSpeed=Speed;
	}
}


/**
 * @fn	GUILane::~GUILane()
 *
 * @brief	Destructor.
 *
 * @author	Ben White
 */

GUILane::~GUILane()//deleting parts in the lane destructor causes problems with Qt
{
	//MyPart* Target;//cycles through all MyParts in the lane
	/*while(!PartsInLane.isEmpty())
	{
		Target=PartsInLane.first();
		PartsInLane.pop_front();
		Target->Remove();//deletes the MyParts Part
	}*/
}

/**
 * @fn	bool GUILane::HereIsAPart(Part* P)
 *
 * @brief	Here is a part.
 *
 * @author	Ben White
 *
 * @param [in,out]	P	If non-null, the p.
 *
 * @return	true if it succeeds, false if it fails.
 */

bool GUILane::HereIsAPart(Part* P)//from feeder signifying that a new part has enetered the lane
{
	int Temp;
	////qDebug("Giving Lane Part");

	P->setParentItem(NULL);
	P->moving = false; // stops the base from moving it.
	P->setX(EndX);//move new part to end of lane
	P->setY(MidY);
	P->setMovementSpeed(Speed);//set speed of new part to current lane speed
	if(NumberOfParts > 0)//if lane is not empty
	{
		//qDebug()<<"X: "<<PartsInLane.last()->getPart();
		if(NumberOfParts < Capacity && PartsInLane.last()->x()+PartSize < EndX)//makes sure there is enough room on the lane
		{
			PartsInLane.push_back(P);//adds part to the list
			//M->getPart()->moveTo((this->x())+(qreal)(PartSize*NumberOfParts),PartsInLane[NumberOfParts]->getPart()->y());//set the part moving
			NumberOfParts++;//increments to reflect adding a part
			//qDebug("Part Given Lane");
			return true;//let feeder know part taken
		}
		else//lane is full
			//qDebug("Part not Given Lane");
			return false;//lets feeder know part not taken
	}
	//if lane is empty
	PartsInLane.push_back(P);
	//M->getPart()->moveTo((this->x())+(qreal)(PartSize*NumberOfParts),PartsInLane[NumberOfParts]->getPart()->y());
	NumberOfParts++;
	////qDebug("Part Given Lane");
	return true;
}

/**
 * @fn	void GUILane::Start(int speed)
 *
 * @brief	Starts.
 *
 * @author	Ben White
 *
 * @param	speed	The speed.
 */

void GUILane::Start(float speed)
{
	if(!Broken)
	{
		Speed=speed;
		LastSpeed=Speed;
		Running=true;
		for(int ii=0 ; ii<NumberOfParts ; ii++)//loop through all parts in lane and set speed=Speed
		{
			PartsInLane[ii]->setMovementSpeed(Speed);
		}
	}
}

/**
 * @fn	void GUILane::Stop()
 *
 * @brief	Stops this object.
 *
 * @author	Ben White
 */

void GUILane::Stop()
{
	Speed=0;
	Running=false;
	for(int ii=0 ; ii<NumberOfParts ; ii++)//loop through all parts in lane and set speed to 0
	{
		PartsInLane[ii]->setMovementSpeed(Speed);
	}
	LastSpeed=0;
}

/**
 * @fn	void GUILane::DoBreak()
 *
 * @brief	Breaks this object. (Same as stop but preserves LastSpeed)
 *
 * @author	Ben White
 */

void GUILane::DoBreak()
{
	GUIBase::DoBreak();
	Speed=0;
	Running=false;
	Broken=true;
	for(int ii=0 ; ii<NumberOfParts ; ii++)//loop through all parts in lane and set speed to 0
	{
		PartsInLane[ii]->setMovementSpeed(Speed);
	}
}

/**
 * @fn	void GUILane::DoFix()
 *
 * @brief	Executes the fix operation.
 *
 * @author	Ben White
 */

void GUILane::DoFix()
{
	GUIBase::DoFix();
	Broken=false;
	Start(LastSpeed);
}

/**
 * @fn	void GUILane::setBroken(bool isBroken)
 *
 * @brief	Sets the broken state.
 *
 * @author	Ben White
 *
 * @param	isBroken	true if this object is broken.
 */

void GUILane::setBroken(bool isBroken)
{
	//Broken=isBroken;
	//float TempSpeed;
	if(isBroken)
	{
		//TempSpeed=LastSpeed;
		this->DoBreak();
		//LastSpeed=TempSpeed;
	}
	else
	{
		this->DoFix();
	}

}

/**
 * @fn	void GUILane::DoJamLane()
 *
 * @brief	Executes the jam lane operation.
 *
 * @author	Ben White
 */

void GUILane::DoJamLane()
{
	int Temp;
	if(Jam==NULL && NumberOfParts!=0)
	{
		Temp=((NumberOfParts*7)%13)%NumberOfParts;
		Jam = PartsInLane[Temp];
	}
}

void GUILane::DoClearJam()
{
	Jam = NULL;
}

/**
 * @fn	void GUILane::setNeighbor(GUILane* neighbor)
 *
 * @brief	Sets a neighbor(Used for part jumping)
 *
 * @author	Ben White
 *
 * @param [in,out]	neighbor	If non-null, the neighbor.
 */

void GUILane::setNeighbor(GUILane* neighbor)
{
	Neighbor=neighbor;
}

/**
 * @fn	void GUILane::JumpLane()
 *
 * @brief	Call from Panel, tells the lane to jump a part
 *
 * @author	Ben White
 */

void GUILane::JumpLane()
{
	int Temp;
	bool Flag;
	if(NumberOfParts==0)
		return;
	Temp=((NumberOfParts*7)%13)%NumberOfParts;//pick a relatively random index number
	if(Neighbor!=NULL)//if the neighbor has been set
	{
		Flag=Neighbor->Jump(PartsInLane[Temp]);//attempt to jump the part
		if(Flag)//if succesfull
		{
			if(PartsInLane[Temp]==Next)//check to see if the jumped part was the Next part
				Next=NULL;//if it was remove the Next index
			PartsInLane.removeAt(Temp);//remove the part from this lane
			NumberOfParts--;//decriment the part counter
		}
	}
	else//ie. Neighbor not set
	{
		//throw part on the ground
		//Grounding.push_back(PartsInLane[Temp]);
		PartsInLane[Temp]->speed=PartsInLane[Temp]->speed*2;
		PartsInLane[Temp]->moveTo(PartsInLane[Temp]->x()+15,PartsInLane[Temp]->y()+25);
		if(PartsInLane[Temp]==Next)//check to see if the jumped part was the Next part
			Next=NULL;//if it was remove the Next index
		PartsInLane.removeAt(Temp);//remove the part from this lane
		NumberOfParts--;//decriment the part counter
	}
}

/**
 * @fn	bool GUILane::Jump(Part* jumper)
 *
 * @brief	Gives the jumping part to the lane's neighbor
 *
 * @author	Ben White
 *
 * @param If non-null, the jumper.
 *
 * @return	true if it succeeds, false if it fails.
 */

bool GUILane::Jump(Part* jumper)
{
	if(NumberOfParts<Capacity)
	{
		for(int ii=0 ; ii<NumberOfParts ; ii++)
		{
			if(PartsInLane[ii]->x()>jumper->x())
			{
				PartsInLane.insert(ii-1,jumper);
				Jumpers.push_back(jumper);
				NumberOfParts++;
				return true;
			}
		}
		PartsInLane.push_back(jumper);
		Jumpers.push_back(jumper);
		NumberOfParts++;
		return true;
	}
	else
	{
		//throw on ground
		jumper->speed=jumper->speed*2;
		if(Neighbor->y()>this->y())//this is the top lane
		{
			jumper->moveTo(jumper->x()-50,this->y()-15);
		}
		else//this is the bottom lane
		{
			jumper->moveTo(jumper->x()-50,this->y()+25+Width);
		}
		jumper->PartFellOnFloor();
		return true;//change this to true after throw on ground is implemented
	}
	return false;
}




/**
 * @fn	void GUILane::advance(int phase)
 *
 * @brief	Advances.
 *
 * @author	Ben White
 *
 * @param	phase	The phase.
 */

void GUILane::advance(int phase)
{
	bool Flag;
	
	if(phase==1 && Running)//if lane is running and frame is in the correct phase
	{
		//////////////////////////////////////////////////////
		//					Part Animation					//
		//////////////////////////////////////////////////////
		if(!PartsInLane.isEmpty())//if lane is not empty
		{
				//////////////////////////
				//	Move the first part	// 
				//////////////////////////
			if(PartsInLane.front()->x()>this->x()+Speed && PartsInLane.front()!=Jam)//if the first part has not reached the end of the lane
			{
				PartsInLane.front()->setX(PartsInLane.front()->x()-Speed);//move the first part according to its speed
			}
			else if(PartsInLane.front()!=Jam)//if that part has or will reach the end of the lane this frame
				PartsInLane.front()->setX(this->x());//move it to the end of the lane
				////////////////////////////
				//	Move all other parts  //
				////////////////////////////
			for(int ii=1 ; ii<NumberOfParts ; ii++)//loop through all parts in the lane(except the first part)
			{
				if(PartsInLane[ii]->x()>PartsInLane[ii-1]->x()+PartSize+Speed && PartsInLane[ii]!=Jam)//if there is enough room between the parts
				{
					PartsInLane[ii]->setX(PartsInLane[ii]->x()-Speed);//move the ii'th part according to its speed
				}
				else if(PartsInLane[ii]!=Jam)//if there is not enough room between parts
					PartsInLane[ii]->setX(PartsInLane[ii-1]->x()+PartSize);//move the ii'th part to the back of the (ii-1)'th part
			}
				////////////////////////////
				//	 Move Jumping Parts   //
				////////////////////////////
			for(int ii=0 ; ii<Jumpers.length() ; ii++)
			{
				if(Jumpers[ii]->y()>MidY+2*Jumpers[ii]->speed)
				{
					Jumpers[ii]->setY(Jumpers[ii]->y()-2*Jumpers[ii]->speed);
				}
				else if(Jumpers[ii]->y()<MidY-2*Jumpers[ii]->speed)
				{
					Jumpers[ii]->setY(Jumpers[ii]->y()+2*Jumpers[ii]->speed);
				}
				else
				{
					Jumpers[ii]->setY(MidY);
					Jumpers[ii]->setMovementSpeed(Speed);
					Jumpers.removeAt(ii);
				}
			}
			//////////////////////////////////////////////////////
			//				Part Calculations					//
			//////////////////////////////////////////////////////
			if(Next==NULL && PartsInLane.front()->x()==this->x())//check to see if the first part is at the end of the lane
			{
				Next=PartsInLane.front();//set the next pointer
			}
			else if(Next!=NULL)//check to see if a part was already at the end of the lane
			{
				Flag=Nest->givePart(Next);//attempt to give nest the part
				if(Flag)//nest returns true if part is taken
				{
					Next=NULL;//remove the reference to the removed part
					
					PartsInLane.pop_front();
					
					NumberOfParts--;//decriment the part counter
					/*for(int ii=0 ; ii<NumberOfParts ; ii++)//loop through all parts in the lane
					{//adjust the move to value
						PartsInLane[ii]->getPart()->moveTo((this->x())+(qreal)(PartSize*ii),PartsInLane[ii]->getPart()->y());
					}*/
				}
			}
		}
	}
	
	
	GUIBase::advance(phase);
}

